/**
 * tftp.h
 * TFTP Client functions.
 * By Group 1
 */
#include "tftpclient.h"
#include <iostream>
#include <fstream>
#include <cstdlib>

static string hostAddress;

void loadHostAddress(const char* address)
{
    hostAddress = address;
}

void printHostAddress()
{
    cout << "Host address: " << hostAddress << endl;
}

void TFTPsendFile(string fileName)
{
    PolonetConn conn;
    if(connectToServer(conn,hostAddress.c_str()))
    {
        cout << "Connection to server successful..." << endl;
        string::size_type locbar = fileName.find( "/", 0 );

        if( locbar != string::npos )
        {
            cout << "File access violation, no directories are allowed." << endl;
        }
        else
        {
            ifstream ifs ( fileName.c_str() , ifstream::binary );
            if(ifs.good())
            {
                cout << fileName << " opened, starting transmission..." << endl;
                transmitWRQPacket(conn,fileName.c_str());

                short receptionCounter;
                char* receptionBuffer = new char[BUFFER_SIZE];
                loadBuffer(conn, receptionBuffer, BUFFER_SIZE);
                bool transferOK = true;

                switch (getPacketType(receptionBuffer))
                {
                case ACK:
                    if (readACKPacket(receptionCounter, receptionBuffer))
                    {
                        if (receptionCounter != 0)
                        {
                            cout << "An error has ocurred with the transmission, aborting..." << endl;
                            transferOK = false;
                        }
                    }
                    else
                    {
                        cout << "Packet got corrupted during execution, terminating server." << endl;
                        exit(1);
                    }
                    break;
                case ERROR:
                    char* errmsg;
                    short errorNumber;
                    readERRORPacket(errmsg,errorNumber, receptionBuffer);
                    cout << "The error " << errorNumber << " has ocurred, which included this message: " << errmsg << endl;
                    transferOK = false;
                    break;
                default:
                    cout << "An error has ocurred with the transmission, aborting..." << endl;
                    transferOK = false;
                }

                short counter = 1;
                int packetCount = 0;
                bool connected = true;

                char* auxBuffer = new char[512];
                while(ifs.eof() == false && transferOK && connected)
                {
                    ifs.read(auxBuffer,512);
                    int readCount = ifs.gcount();
                    transmitDATAPacket(conn,counter,auxBuffer,readCount);

                    packetCount+=readCount;
                    cout << "\r" << packetCount << " bytes transfered...";
                    cout.flush();

                    loadBuffer(conn, receptionBuffer, BUFFER_SIZE);
                    switch (getPacketType(receptionBuffer))
                    {
                    case ACK:
                        if (readACKPacket(receptionCounter, receptionBuffer))
                        {
                            if (receptionCounter != counter)
                            {
                                cout << "An error has ocurred with the transmission, aborting..." << endl;
                                transferOK = false;
                            }
                        }
                        else
                        {
                            cout << "Packet got corrupted during execution, terminating client." << endl;
                            exit(1);
                        }
                        break;
                    case ERROR:
                        char* errmsg;
                        short errorNumber;
                        readERRORPacket(errmsg,errorNumber, receptionBuffer);
                        cout << "The error " << errorNumber << " has ocurred, which included this message: " << errmsg << endl;
                        transferOK = false;
                        break;
                    default:
                        cout << "An error has ocurred with the transmission, aborting..." << endl;
                        transferOK = false;
                    }
                    counter++;
                    if (!isConnected(conn))
                    {
                        connected = false;
                    }
                }
                if(transferOK)
                    cout << "\r" << packetCount << " bytes have been successfully transfered to the server..." << endl;
                delete[] auxBuffer;
                delete[] receptionBuffer;
            }
            else
            {
                cout << "File could not be opened or does not exist." << endl;
            }
            ifs.close();
        }
        disconnectFromServer(conn);
    }
    else
    {
        cout << "Could not connect to server." << endl;
    }
}

void TFTPgetFile(string fileName)
{
    PolonetConn conn;
    if(connectToServer(conn,hostAddress.c_str()))
    {
        cout << "Connection to server successful..." << endl;
        string::size_type locbar = fileName.find( "/", 0 );

        if( locbar != string::npos )
        {
            cout << "File access violation, no directories are allowed." << endl;
        }
        else
        {
            ifstream ifs ( fileName.c_str() , ifstream::binary );
            if(ifs.good())
            {
                cout << "File already exists, rewriting is not allowed." << endl;
                ifs.close();
            }
            else
            {
                ifs.close();

                cout << "Starting reception of " << fileName << endl;
                transmitRRQPacket(conn,fileName.c_str());

                char* receptionBuffer = new char[BUFFER_SIZE];
                char* auxBuffer = new char[512];
                bool transferOK = true;
                bool transferDone = false;
                bool connected = true;
                short blockNumber;
                int receivedBytes = loadBuffer(conn, receptionBuffer, BUFFER_SIZE);
                int receivedPackets = 0; // Incluyo el primero con los datos que recibo.

                if(getPacketType(receptionBuffer) == DATA)
                {
                    ofstream ofs(fileName.c_str(),ios_base::binary);
                    if (ofs.is_open())
                    {
                        while (transferOK && transferDone == false && connected)
                        {
                            switch (getPacketType(receptionBuffer))
                            {
                            case DATA:
                                if (readDATAPacket(auxBuffer, blockNumber, receptionBuffer,receivedBytes))
                                {
                                    receivedPackets+= receivedBytes-4;
                                    cout << "\r" << receivedPackets << " bytes received...";
                                    cout.flush();
                                    ofs.write(auxBuffer,receivedBytes-4);
                                    transmitACKPacket(conn,blockNumber);
                                    if (receivedBytes < 516)
                                        transferDone = true;
                                    else
                                    {
                                        receivedBytes = loadBuffer(conn, receptionBuffer, BUFFER_SIZE);
                                    }
                                }
                                else
                                {
                                    cout << endl << "Packet got corrupted during execution, terminating client." << endl;
                                    exit(1);
                                }
                                break;
                            case ERROR:
                                char* errmsg;
                                short errorNumber;
                                readERRORPacket(errmsg,errorNumber, receptionBuffer);
                                cout << "The error " << errorNumber << " has ocurred, which included this message: " << errmsg << endl;
                                transferOK = false;
                                break;
                            default:
                                cout << "An error has ocurred with the transmission, aborting..." << endl;
                                transferOK = false;
                            }
                            if (!isConnected(conn))
                            {
                                connected = false;
                            }
                        }
                        if(transferOK)
                            cout << "\r" << receivedPackets << " bytes have been successfully retrieved from the server." << endl;

                        delete[] auxBuffer;
                        delete[] receptionBuffer;
                        ofs.close();


                    }
                    else
                    {
                        cout << "Error opening file: " << fileName << endl;
                    }
                }
                else if (getPacketType(receptionBuffer) == ERROR)
                {
                    char* errmsg;
                    short errorNumber;
                    readERRORPacket(errmsg,errorNumber, receptionBuffer);
                    cout << "The error " << errorNumber << " has ocurred, which included this message: " << errmsg << endl;
                }
                else
                {
                    cout << "An unknown error has ocurred, aborting transmission..." << endl;
                }
            }
        }
        disconnectFromServer(conn);
    }
    else
    {
        cout << "Could not connect to server." << endl;
    }
}

void TFTPdie()
{
    cout << "Sending DIE message, server will now shutdown..." << endl;
    PolonetConn conn;
    if(connectToServer(conn,hostAddress.c_str()))
    {
        transmitDIEPacket(conn);
        disconnectFromServer(conn);
    }
    else
    {
        cout << "DIE message transmission aborted..." << endl;
    }
}

void TFTPecho(string message)
{
    if(message.length() > MAX_STR_LENGTH)
        cout << "The message you wrote is too long, please try again with a message shorter than " << MAX_STR_LENGTH << " characters." << endl;
    else
    {
        cout << "Sending ECHO message..." << endl;
        PolonetConn conn;
        if(connectToServer(conn,hostAddress.c_str()))
        {
            char* buffer = new char[BUFFER_SIZE];
            transmitECHOPacket(conn,message.c_str());
            loadBuffer(conn,buffer,BUFFER_SIZE);

            switch (getPacketType(buffer))
            {
            case ECHO:
                char* message;
                if (readECHOPacket(message, buffer))
                {
                    cout << "This is the ECHO message from the server: " << message << endl;
                }
                else
                {
                    cout << "Packet got corrupted during execution, terminating server." << endl;
                    exit(1);
                }
                break;
            case ERROR:
                char* errmsg;
                short errorNumber;
                readERRORPacket(errmsg,errorNumber, buffer);
                cout << "The error " << errorNumber << " has ocurred, which included this message: " << errmsg << endl;
                break;
            default:
                cout << "Wrong packet received as an answer, the server might be a bit drunk..." << endl;
                break;
            }

            disconnectFromServer(conn);
        }
        else
        {
            cout << "ECHO message transmission aborted..." << endl;
        }
    }
}
